package com.hb.B_面向对象.J_lambda和集合.B_集合的高阶函数API

/**
 * 有些时候，我们遇到的集合元素不仅仅是数值、类、字符串这种类型，也可能是集合。
 *  Kotlin中提供了一个flatten为我们处理嵌套集合，通过一个集合的集合来获取集合
 */
fun main() {

    /**
     *
    public fun <T> Iterable<Iterable<T>>.flatten(): List<T> {
    val result = ArrayList<T>()
    for (element in this) {
    result.addAll(element)
    }
    return result
    }
     *
     *  源码解析：
     *      首先声明一个数组result，该数组的长度是嵌套集合中的所有子集合的长度之和。然后遍历这个嵌套集合
     *      将每个自己和中的元素通过addAll()方法添加到result中，最终就得到了一个扁平化的集合。
     *
     *
     *  假如我们并不想直接得到一个扁平化之后的集合，而是希望将子集合中的元素加工一下，然后返回一个"加工"之后
     *  的集合。
     *  比如我们对上面的集合中的元素在*2
     *
     *  flatMap接收了一个函数，该函数的返回值是一个列表，一个由学生姓名组成的列表
     */
    val list = listOf(listOf(1..10), listOf(11..20), listOf(21..30))
    list.flatten().forEach(::println)

    val student1 = Student("student1", 30, "男", 85)
    val student2 = Student("student2", 20, "男", 80)
    val student3 = Student("student3", 25, "女", 82)
    val student4 = Student("student4", 28, "女", 88)
    val student5 = Student("student5", 35, "男", 89)

    var studentList = listOf(listOf(student1, student2), listOf(student3, student4, student5))
    studentList.flatten().map {
        it.name
    }.forEach(::println)

    //flatMap
    studentList.flatMap {
        it.map {
            it.name
        }
    }.forEach(::println)



    val user1 = User("user1", 30, listOf<String>("reading","coding","dancing"))
    val user2 = User("user2", 20, listOf<String>("jump"))
    val user3 = User("user3", 25, listOf<String>("大声叫","游泳"))
    val user4 = User("user4", 28, listOf<String>("钓鱼","足球"))
    val user5 = User("user5", 35, listOf<String>("playing","篮球"))

    //flatmap
    var userList = listOf<User>(user1, user2, user3, user4, user5)
    userList.flatMap {
        it.hobbies
    }.forEach(::println)

    println("--------")
    //flatten
    userList.map {
        it.hobbies
    }.flatten().forEach(::println)

    /**
     * 通过这个例子我们发现，flatMap是将列表进行map操作，然后再进行flatten操作的，而且这个例子中使用
     * flatmap更加简洁。
     *
    public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
    }

    public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
    for (element in this) {
    val list = transform(element)
    destination.addAll(list)
    }
    return destination
    }
     *
     *  可以看到，flatMap接收一个函数：transform
     * transform: (T) -> Iterable<R>，transform函数接收一个参数，该参数一般
     * 为嵌套列表中的某个子列表，返回值为一个列表。比如我们前面用flatMap获取爱好列表的时候
     *
     *  flatMapTo 接收两个参数，一个参数为列表，该列表为一个空的列表，另外一个参数为一个函数，该函数
     *  的返回值为一个序列。flatMapTo的实现很简单，首先遍历集合中的元素，然后将每个元素传入函数transform
     *  中得到一个列表，然后将这个列表中的所有元素添加到空列表destination,这样最终得到一个经过transform函数
     *  处理过扁平化的列表。
     *
     *  flatMap其实可以看做由flatten和map进行组个之后的方法，组合方式根据具体情况来定。当我们仅仅需要
     *  对一个集合进行扁平化操作的时候，使用flatten就可以了。如果需要对其中的元素进行一些"加工"，那我们可以
     *  考虑使用flatMap.
     *  */


}

data class User(val name:String,val age:Int,val hobbies:List<String>)